package com.striker.nettyconn;

import java.util.Scanner;
import java.util.concurrent.TimeUnit;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.Data;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//import static java.lang.Thread.sleep;

@Data
public class Client {
    private final Log logger = LogFactory.getLog(Client.class);

    private NioEventLoopGroup worker = new NioEventLoopGroup();

    private Channel channel;

    private Bootstrap bootstrap;

    private long loginUin;

    private long peerUin;

    public static void main(String[] args) throws InterruptedException {
        if(args.length < 2){
            throw new RuntimeException("参数不足");
        }

        Client  client = new Client();
        client.loginUin = Integer.parseInt(args[0]);
        client.peerUin = Integer.parseInt(args[1]);

        client.start();

        client.login();
        client.sendData();
        //client.getOfflineMsg();
        // ---- client /127.0.0.1:55264 reader timeOut, --- close it
        // ---/127.0.0.1:55264----- channel is Inactive
        //client.sendProtoData();//todo:不起作用?
    }

    private void start() throws InterruptedException {
        bootstrap = new Bootstrap();        
        bootstrap.group(worker)
        .channel(NioSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
        .handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                // TODO Auto-generated method stub
                ChannelPipeline pipeline = ch.pipeline();
                // 添加长度字段×××
                // 在MessagePack×××之前增加LengthFieldBasedFrameDecoder，用于处理半包消息
                // 它会解析消息头部的长度字段信息，这样后面的MsgpackDecoder接收到的永远是整包消息
                // pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));

                pipeline.addLast(new IdleStateHandler(0,0,5));

                pipeline.addLast(new MsgPckDecode());

                // 在MessagePack编码器之前增加LengthFieldPrepender，它将在ByteBuf之前增加2个字节的消息长度字段
                // ch.pipeline().addLast("frameEncoder", new LengthFieldPrepender(2));

                pipeline.addLast(new MsgPckEncode());

                logger.info("add Client3Handler");
                pipeline.addLast(new Client3Handler(Client.this));              
            }           
        }); 
        doConnect();
    }

    /**
     * 连接服务端 and 重连
     */
    protected void doConnect() throws InterruptedException {

        if (channel != null && channel.isActive()){
            return;
        }       
        ChannelFuture connect = bootstrap.connect("127.0.0.1", 8081).sync();
        //实现监听通道连接的方法
        connect.addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {

                if(channelFuture.isSuccess()){
                    channel = channelFuture.channel();
                    logger.info("客户端|连接成功|done:"+channelFuture.isDone());
                    if(channelFuture.isDone()) {
                        //sendData(); //这里发为什么会导致连接中断? //todo
                    }
                    //login();
                }else{
                    logger.info("每隔2s重连....");
                    channelFuture.channel().eventLoop().schedule(new Runnable() {

                        @Override
                        public void run() {
                            // TODO Auto-generated method stub
                            try {
                                doConnect();
                            } catch (InterruptedException e) {
                                System.out.println("发生异常");
                                e.printStackTrace();
                            }
                        }
                    },2,TimeUnit.SECONDS);
                }
            }
        });     
    }

    /**
     * 向服务端发送消息
     */
    private void login() throws InterruptedException {
        //sleep(500);
        if(channel != null && channel.isActive()){
            logger.info("客户端|login|登录|uin:"+loginUin);
            Model model = new Model();
            model.setFromUin(loginUin);
            model.setToUin(peerUin);

            model.setType(TypeData.LOGIN);

            model.setBody("login");

            channel.writeAndFlush(model);
        }
    }

    /**
     * 向服务端发送消息
     */
    public void sendData() throws InterruptedException {
        //sleep(1000);
        Scanner sc= new Scanner(System.in);
        logger.info("客户端|sendData|开始发");
        for (int i = 0; i < 1000; i++) {
            if(channel != null && channel.isActive()){
                //获取一个键盘扫描器
                String nextLine = sc.nextLine();
                Model model = new Model();
                model.setFromUin(loginUin);
                model.setToUin(peerUin);

                model.setType(TypeData.CUSTOMER);
//                if(i == 0){
//                    model.setType(TypeData.LOGIN);
//                }

                model.setBody(nextLine);
                logger.info("客户端|sendData|i:" + i);

                channel.writeAndFlush(model);
            }
        }
    }

    private void getOfflineMsg()throws InterruptedException{
        //sleep(1000);//todo:不sleep channel==null
        logger.info("客户端|getOfflineMsg|发请求");
        Model model = new Model();
        model.setFromUin(loginUin);
        model.setToUin(peerUin);

        model.setType(TypeData.C2COfflineMsg);
        channel.writeAndFlush(model);
    }

    /**
     * 向服务端发送消息 toto protoBuf未用起来
     */
    private void sendProtoData() throws InterruptedException {
        //sleep(1000);
        Scanner sc= new Scanner(System.in);//读取键盘输入的内容
        for (int i = 0; i < 1000; i++) {
            if(channel != null && channel.isActive()){
                logger.info("客户端|sendProtoData|"+i);
                //1、 创建Builder
                MessageProto.Message.Builder builder = MessageProto.Message.newBuilder();
                //2、 设置Person的属性
                builder.setId("id"+i);
                builder.setType(0);
                builder.setContent("hello|"+i);
                //3、 创建
                MessageProto.Message message = builder.build();
                //4、序列化
                //5、将data保存在本地或者是传到网络
                channel.writeAndFlush(message);
            }
        }
    }
}
